"""
提示工程类型定义模块

定义提示词相关的数据类型和枚举。
"""

from dataclasses import dataclass
from enum import Enum
from typing import List, Dict, Any, Optional


class PromptStyle(Enum):
    """
    提示词风格枚举

    定义不同的提示词风格，用于适配不同的对话场景和用户偏好。
    """
    FORMAL = "formal"          # 正式风格 - 适合专业场景
    FRIENDLY = "friendly"      # 友好风格 - 适合日常对话
    CONCISE = "concise"        # 简洁风格 - 适合快速问答
    DETAILED = "detailed"      # 详细风格 - 适合深度分析
    TECHNICAL = "technical"    # 技术风格 - 适合技术讨论
    CREATIVE = "creative"      # 创意风格 - 适合创意写作
    EDUCATIONAL = "educational" # 教育风格 - 适合教学场景

    def get_description(self) -> str:
        """获取风格描述"""
        descriptions = {
            PromptStyle.FORMAL: "正式、专业的表达方式",
            PromptStyle.FRIENDLY: "友好、轻松的对话风格",
            PromptStyle.CONCISE: "简洁、直接的表达方式",
            PromptStyle.DETAILED: "详细、全面的分析风格",
            PromptStyle.TECHNICAL: "专业、技术的术语风格",
            PromptStyle.CREATIVE: "创意、富有想象力的风格",
            PromptStyle.EDUCATIONAL: "教学、循序渐进的风格"
        }
        return descriptions.get(self, "未知风格")

    def is_suitable_for_context_length(self, context_length: int) -> bool:
        """
        判断风格是否适合给定的上下文长度

        Args:
            context_length: 上下文长度（字符数）

        Returns:
            bool: 是否适合
        """
        style_suitability = {
            PromptStyle.FORMAL: (100, float('inf')),      # 适合中等以上长度
            PromptStyle.FRIENDLY: (0, float('inf')),      # 适合任何长度
            PromptStyle.CONCISE: (0, 1000),               # 适合短上下文
            PromptStyle.DETAILED: (500, float('inf')),    # 适合长上下文
            PromptStyle.TECHNICAL: (200, float('inf')),    # 适合中等以上长度
            PromptStyle.CREATIVE: (0, float('inf')),       # 适合任何长度
            PromptStyle.EDUCATIONAL: (100, float('inf'))  # 适合中等以上长度
        }

        min_len, max_len = style_suitability.get(self, (0, float('inf')))
        return min_len <= context_length <= max_len


@dataclass
class PromptTemplate:
    """
    提示词模板数据类

    封装提示词模板的所有必要信息，支持动态变量替换和风格管理。
    """
    name: str
    template: str
    description: str
    style: PromptStyle
    required_vars: List[str]
    optional_vars: Optional[List[str]] = None
    examples: Optional[List[Dict[str, Any]]] = None
    metadata: Optional[Dict[str, Any]] = None

    def __post_init__(self):
        """初始化后处理"""
        if self.optional_vars is None:
            self.optional_vars = []
        if self.examples is None:
            self.examples = []
        if self.metadata is None:
            self.metadata = {}

        # 确保必需变量在模板中存在
        self._validate_template_format()

    def _validate_template_format(self) -> None:
        """验证模板格式"""
        import re

        # 查找模板中的所有变量
        template_vars = set(re.findall(r'\{(\w+)\}', self.template))

        # 检查必需变量
        missing_required = set(self.required_vars) - template_vars
        if missing_required:
            raise ValueError(
                f"模板 '{self.name}' 中缺少必需变量: {', '.join(missing_required)}"
            )

        # 检查模板中是否有未声明的变量
        undeclared_vars = template_vars - set(self.required_vars) - set(self.optional_vars)
        if undeclared_vars:
            raise ValueError(
                f"模板 '{self.name}' 中存在未声明的变量: {', '.join(undeclared_vars)}"
            )

    def format(self, variables: Dict[str, Any], strict: bool = True) -> str:
        """
        格式化模板

        Args:
            variables: 变量字典
            strict: 是否严格模式（缺少变量时是否抛出异常）

        Returns:
            str: 格式化后的提示词

        Raises:
            ValueError: 缺少必需变量时抛出（仅在strict模式）
        """
        # 检查必需变量
        missing_vars = set(self.required_vars) - set(variables.keys())
        if missing_vars and strict:
            raise ValueError(f"缺少必需变量: {', '.join(missing_vars)}")

        # 为可选变量提供默认值
        formatted_vars = {}
        for var in self.required_vars:
            if var in variables:
                formatted_vars[var] = variables[var]

        for var in self.optional_vars:
            formatted_vars[var] = variables.get(var, "")

        try:
            return self.template.format(**formatted_vars)
        except KeyError as e:
            if strict:
                raise ValueError(f"模板变量未提供: {e}")
            # 非严格模式下，将未提供变量替换为空字符串
            return self.template.format(**{k: v for k, v in formatted_vars.items() if k in variables})

    def validate_variables(self, variables: Dict[str, Any]) -> List[str]:
        """
        验证变量字典

        Args:
            variables: 要验证的变量字典

        Returns:
            List[str]: 问题列表，空列表表示验证通过
        """
        issues = []

        # 检查必需变量
        missing_required = set(self.required_vars) - set(variables.keys())
        if missing_required:
            issues.append(f"缺少必需变量: {', '.join(missing_required)}")

        # 检查变量类型（如果有类型要求）
        if self.metadata:
            var_types = self.metadata.get('var_types', {})
            for var, expected_type in var_types.items():
                if var in variables and not isinstance(variables[var], expected_type):
                    issues.append(f"变量 '{var}' 类型错误: 期望 {expected_type.__name__}, 实际 {type(variables[var]).__name__}")

        return issues

    def get_example(self, index: int = 0) -> Optional[Dict[str, Any]]:
        """
        获取示例

        Args:
            index: 示例索引

        Returns:
            Optional[Dict[str, Any]]: 示例字典，不存在时返回None
        """
        if 0 <= index < len(self.examples):
            return self.examples[index]
        return None

    def add_example(self, variables: Dict[str, Any], description: str = "") -> None:
        """
        添加示例

        Args:
            variables: 变量字典
            description: 示例描述
        """
        example = {
            "variables": variables,
            "description": description,
            "formatted": self.format(variables)
        }
        self.examples.append(example)

    def get_complexity_score(self) -> float:
        """
        计算模板复杂度得分

        Returns:
            float: 复杂度得分 (0-1, 越高越复杂)
        """
        # 基于多个因素计算复杂度
        factors = []

        # 变量数量因素
        var_count = len(self.required_vars) + len(self.optional_vars)
        var_complexity = min(var_count / 10, 1.0)  # 10个变量为满分
        factors.append(var_complexity)

        # 模板长度因素
        length_complexity = min(len(self.template) / 2000, 1.0)  # 2000字符为满分
        factors.append(length_complexity)

        # 结构复杂度（基于特殊字符和格式）
        structure_markers = ['【', '】', '\n', '：', '1.', '2.', '3.']
        structure_count = sum(self.template.count(marker) for marker in structure_markers)
        structure_complexity = min(structure_count / 20, 1.0)  # 20个结构标记为满分
        factors.append(structure_complexity)

        return sum(factors) / len(factors)

    def clone(self, **kwargs) -> 'PromptTemplate':
        """
        克隆模板，支持覆盖属性

        Args:
            **kwargs: 要覆盖的属性

        Returns:
            PromptTemplate: 新的模板实例
        """
        import copy

        # 深拷贝所有属性
        new_template = copy.deepcopy(self)

        # 覆盖指定属性
        for key, value in kwargs.items():
            if hasattr(new_template, key):
                setattr(new_template, key, value)

        return new_template

    def __str__(self) -> str:
        """返回模板的字符串表示"""
        return (
            f"PromptTemplate({self.name}) | "
            f"风格: {self.style.value} | "
            f"变量: {len(self.required_vars) + len(self.optional_vars)} | "
            f"复杂度: {self.get_complexity_score():.2f}"
        )


class PromptCategory(Enum):
    """提示词分类枚举"""
    RAG = "rag"                    # RAG相关
    CHAT = "chat"                  # 对话相关
    ANALYSIS = "analysis"          # 分析相关
    CREATION = "creation"          # 创作相关
    TRANSLATION = "translation"    # 翻译相关
    SUMMARIZATION = "summarization" # 摘要相关
    QA = "qa"                      # 问答相关
    CODE = "code"                  # 代码相关


@dataclass
class PromptUsageStats:
    """提示词使用统计"""
    template_name: str
    usage_count: int = 0
    success_rate: float = 1.0
    avg_response_length: float = 0.0
    last_used: Optional[str] = None
    user_satisfaction: float = 0.0

    def update_usage(
        self,
        response_length: int,
        success: bool = True,
        satisfaction: Optional[float] = None
    ) -> None:
        """
        更新使用统计

        Args:
            response_length: 响应长度
            success: 是否成功
            satisfaction: 用户满意度 (0-1)
        """
        from datetime import datetime

        self.usage_count += 1
        self.last_used = datetime.now().isoformat()

        # 更新成功率
        total_success = self.success_rate * (self.usage_count - 1) + (1.0 if success else 0.0)
        self.success_rate = total_success / self.usage_count

        # 更新平均响应长度
        total_length = self.avg_response_length * (self.usage_count - 1) + response_length
        self.avg_response_length = total_length / self.usage_count

        # 更新用户满意度
        if satisfaction is not None:
            if self.user_satisfaction == 0:
                self.user_satisfaction = satisfaction
            else:
                self.user_satisfaction = (self.user_satisfaction + satisfaction) / 2